package com.example.order.itheima;


import com.example.order.itheima.annotation.Clients;
import com.example.order.itheima.annotation.EnableClients;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 扫包
 * 注册标注了该注解的bean
 */

@Slf4j
public class ClientRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware  {

    private Environment environment;

    private ResourceLoader resourceLoader;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 拿到 要扫描的 包路径
        Set<String> basePackages = getBasePackages(metadata);
        // 扫描器
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        // 配置 scanner
        scanner.setResourceLoader(this.resourceLoader);
        // 配置 filter
        scanner.addIncludeFilter(new AnnotationTypeFilter(Clients.class));
        // do scan
        for (String basePackage : basePackages) {
            // 查找该包下的 候选
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            // 处理
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition)  {
                    //
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    // 拿到元数据信息
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    registerClient(registry,annotationMetadata);
                }
            }
        }
    }

    private ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false,this.environment){
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                // 必须要求是接口
                AnnotationMetadata md = beanDefinition.getMetadata();
                if (md.isInterface()) {
                    return true;
                }
                return false;
            }
        };
    }

    //解析注解元数据信息并注册bean
    private void registerClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata) {
        // 接口 全限定名称
        String className = annotationMetadata.getClassName();

        // 获取 Clients注解配置的属性值
        Map<String, Object> clientsAttributes = annotationMetadata.getAnnotationAttributes(Clients.class.getName());
        // 生成 ClientFactoryBean beanDefinetion
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ClientFactoryBean.class);
        builder.addPropertyValue("type",className);
        builder.addPropertyValue("serviceName",getServiceName(clientsAttributes));
        builder.addPropertyValue("url",getUrl(clientsAttributes));
        builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        // generate bd
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className);
        BeanDefinitionReaderUtils.registerBeanDefinition(holder,registry);//多一个别名注册
    }

    private String getUrl(Map<String, Object> clientsAttributes) {
        return (String) clientsAttributes.get("url");
    }

    private String getServiceName(Map<String, Object> clientsAttributes) {
        String ServiceName = (String) clientsAttributes.get("value");
        if (!StringUtils.hasText(ServiceName)) {
            ServiceName = (String) clientsAttributes.get("name");
        }
        return ServiceName;
    }

    private Set<String> getBasePackages(AnnotationMetadata metadata) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableClients.class.getName());
        Set<String> result = new HashSet<>();
        // find value
        String[]  value = (String[]) annotationAttributes.get("value");
        for (String basePackage : value) {
            if (StringUtils.hasText(basePackage)) {
                result.add(basePackage);
            }
        }
        // find basePackages
        String[]  basePackages = (String[]) annotationAttributes.get("basePackages");
        for (String basePackage : basePackages) {
            if (StringUtils.hasText(basePackage)) {
                result.add(basePackage);
            }
        }
        return result;
    }
}
